/*
 * @Author: fanjs
 * @Date: 2024-03-21 16:02:00
 * @Description: 账单管理 API
 */
import { api, auth } from '@core/decorator'
import BillModel, { BillAttributes } from '@app/model/bill'
import { AuthRouterContext } from 'router'
import RecordModel from '@app/model/record'
import InterestLogModel from '@app/model/interest-log'
import { DateUtil } from '@core/util'
import { Transaction, Op } from 'sequelize'
import dayjs from 'dayjs'
@api.controller('/v1/bill')
class BillController {
  /**
   * 获取账单列表
   * @param name 姓名（可选）
   * @param page 页码
   * @param pageSize 每页数量
   */
  @api.get('/list')
  @api.auth('UserScope')
  @auth.login_required
  async getBillList(ctx: AuthRouterContext) {
    const { uid } = ctx.auth
    const { name, page = 1, pageSize = 10 } = ctx.query as any

    const result = await BillModel.getBillList(uid, {
      name,
      page: Number(page),
      pageSize: Number(pageSize)
    })

    throw new global.errs.Success(result)
  }

  /**
   * 创建账单
   * @param name 姓名
   * @param phone 手机号码
   * @param type 账单类型
   * @param principal 本金总额
   * @param rateType 利率类型
   * @param rate 利率
   * @param startDate 开始时间
   * @param nextDate 下一计息日
   * @param nextInterest 下次利息
   */
  @api.post('/create')
  @api.auth('UserScope')
  @auth.login_required
  async createBill(ctx: AuthRouterContext) {
    const { uid } = ctx.auth
    const {
      name,
      phone,
      type,
      principal,
      rateType,
      rate,
      startDate,
      nextDate,
      nextInterest,
      totalInterest,
    } = ctx.request.body as any

    const createData: BillAttributes = { name,  phone, type, principal, rateType, rate, startDate, nextDate, nextInterest }

    // 存在空值拦截
    if (Object.values(createData).some(item => !item)) throw new global.errs.ParameterException('请填写完整信息')

    // 补字段 => 本金、已操作本金、总利息、剩余利息、已操作利息、是否已结清
    createData.principal = createData.principal
    createData.settledPrincipal = 0
    createData.additionalPrincipal = 0
    createData.totalInterest = totalInterest || 0
    createData.remainingInterest = totalInterest ||0
    createData.settledInterest = 0
    createData.isSettled = false
    createData.hasRecord = false

    const bill = await BillModel.createBill(uid, createData)
    if (!bill) throw new global.errs.ParameterException('创建失败')

    throw new global.errs.Success(true, null, '创建成功')
  }

  /**
   * 更新账单
   * @param id 账单ID
   * @param data 更新数据
   */
  @api.post('/update/:id')
  @api.auth('UserScope')
  @auth.login_required
  async updateBill(ctx: AuthRouterContext) {
    const { uid, nickname } = ctx.auth
    const { id } = ctx.params
    const requestData: Partial<BillAttributes> = ctx.request.body as any
    if (!requestData) throw new global.errs.ParameterException('未上传更新数据')

    // 获取 Sequelize 模型实例
    const billInstance = await BillModel.getBillById(Number(id))
    if (!billInstance) throw new global.errs.NotFound('账单不存在')
    const originalBill = billInstance.toJSON()

    // 记录操作前的数据
    const beforePrincipal = Number(originalBill.principal) // 账单剩余本金
    const beforeTotalInterest = Number(originalBill.totalInterest) // 账单总利息
    const beforeInterest = Number(originalBill.remainingInterest) // 账单剩余利息
    const beforeRate = Number(originalBill.rate) // 原利率值
    const beforeRateType = originalBill.rateType // 原利率类型

    // 账单开始时间 > 当前时间 = 直接更新数据
    if (dayjs(originalBill.startDate).isAfter(dayjs())) {
      await billInstance.update(requestData)
      throw new global.errs.Success(true, null, '更新成功')
    }

    /**  上一个计息日期 */
    const lastInterestDate = BillModel.calculateLastInterestDate(originalBill.nextDate, originalBill.rateType)
    /** 距离上次可计次数 */
    const count = Math.floor(DateUtil.diffMonthsOrDays(lastInterestDate, new Date(), beforeRateType === 'M' ? 'month' : 'day'))
    /** 根据次数计算本次利息 - 叠加至账单剩余利息中 */
    const currentInterest = RecordModel.calculateInterest(
      beforeRate,
      beforePrincipal,
      count
    )
    const afterInterest = beforeInterest + currentInterest
    
    /** 计算下次计息日期 */
    const rateType = requestData.rateType || beforeRateType
    const nextDate = DateUtil.formatDate(DateUtil.addMonthsOrDays(DateUtil.getCurrentDateTime(), 1, rateType === 'M' ? 'month' : 'day'))
    /** 计算下次利息 只有一次 */
    const nextInterest = RecordModel.calculateInterest(
      requestData.rate || beforeRate,
      requestData.principal || beforePrincipal,
      1
    )
    /** 
     * 根据本次提交的数据，重新计算相关金额账单字段
     * 1. 利息总额
     * 2. 剩余利息
     * 3. 下周期利息
     * 4. 计息周期更变
     * 5. 记录操作
     **/
    const billUpdateData: any = {
      ...requestData, // 保留基础信息更新
      totalInterest: beforeTotalInterest + currentInterest,
      remainingInterest: afterInterest,
      nextInterest,
      nextDate,
      hasRecord: true,
    }

    /** 更新账单 */
    await billInstance.update(billUpdateData)

    /** 创建操作记录 */
    const recordRemark = []
    if (requestData.principal !== undefined && requestData.principal !== beforePrincipal) {
      recordRemark.push('本金调整')
    }
    if (requestData.rateType !== undefined && requestData.rateType !== beforeRateType) {
      recordRemark.push('利率类型调整')
    }
    if (requestData.rate !== undefined && requestData.rate !== beforeRate) {
      recordRemark.push('利率值调整')
    }

    /** 
     * 创建操作记录
     * 1. 操作金额 = 现本金 - 原本金
     * 2. 账单操作类型
     * 3. 操作前本金
     * 4. 操作后本金
     * 5. 操作前利息
     * 6. 操作后利息
     * 7. 操作人
     * 8. 操作人昵称
     * 8. 备注
     **/
    await RecordModel.createRecord({
      billId: Number(id),
      otherType: '账单编辑',
      amount: (requestData.principal as number) - beforePrincipal,
      beforePrincipal,
      afterPrincipal: requestData.principal as number,
      beforeInterest,
      afterInterest,
      operator: uid.toString(),
      operatorName: nickname || '',
      remark: `编辑-${recordRemark.length ? recordRemark.join('、') : '其他'}`
    })

    throw new global.errs.Success(true, null, '更新成功')
  }

  /**
   * 删除账单
   * @param id 账单ID
   */
  @api.post('/delete/:id')
  @api.auth('UserScope')
  @auth.login_required
  async deleteBill(ctx: AuthRouterContext) {
    const { uid } = ctx.auth
    const { id } = ctx.params
    if (!id) throw new global.errs.ParameterException('账单ID不能为空')
    await BillModel.deleteBill(uid, Number(id))
    throw new global.errs.Success(true, null, '删除成功')
  }

  /**
   * 获取账单详情
   * @param id 账单ID
   */
  @api.get('/detail/:id')
  @api.auth('UserScope')
  @auth.login_required
  async getBillDetail(ctx: AuthRouterContext) {
    const { uid } = ctx.auth
    const { id } = ctx.params

    if (!id) throw new global.errs.ParameterException('账单ID不能为空')

    const bill = await BillModel.getBillDetail(uid, Number(id))
    if (!bill) throw new global.errs.NotFound('账单不存在')

    throw new global.errs.Success(bill)
  }

  /**
   * 批量自动计息
   * 遍历所有未结清的账单，计算从上次计息到最近计息日的利息
   */
  @api.post('/auto-interest')
  @api.auth('UserScope')
  @auth.login_required
  async autoInterest(ctx: AuthRouterContext) {
    const { uid } = ctx.auth
    
    const now = new Date() // 获取当前时间
    
    // 获取所有需要计息的账单（未结清且计息日已到）
    const bills = await BillModel.getBillsNeedInterest(uid, now)
    if (!bills.length) throw new global.errs.APIException('没有需要计算的账单')

    let successCount = 0
    let failCount = 0
    const results: Array<{
      billId: number;
      name: string;
      currentInterest?: number;
      error?: string;
      status: 'success' | 'fail';
    }> = []

    // 使用事务处理所有账单
    await (BillModel as any).sequelize.transaction(async (transaction: Transaction) => {
      for (const billInstance of bills) {
        try {
          const bill = billInstance.toJSON()
          const beforePrincipal = Number(bill.principal)
          const beforeInterest = Number(bill.remainingInterest)
          const beforeTotalInterest = Number(bill.totalInterest)
 
          const lastInterestDate = BillModel.calculateLastInterestDate(bill.nextDate, bill.rateType) // 上一个计息日期
          const count = RecordModel.calculateCount(lastInterestDate, new Date(), bill.rateType) // 计算计息次数
          const currentInterest = RecordModel.calculateInterest(bill.rate, beforePrincipal, count) //根据次数计算利息

          const afterInterest = beforeInterest + currentInterest // 利息

          /** 
           * 创建操作记录
           * 1. 操作后利息 = 操作前利息 + 本次利息
           * 2. 计息天数 = 可计次数 * 计息步长
           **/
          await RecordModel.createRecord({
            billId: bill.id,
            billType: bill.type,
            needMoneyType: false,
            otherType: '自动计息',
            amount: currentInterest,
            beforePrincipal,
            afterPrincipal: beforePrincipal,
            beforeInterest,
            afterInterest,
            operator: uid.toString(),
            operatorName: ctx.auth.nickname || '',
            remark: `自动计息（${count}次）`
          }, { transaction })

          // 创建计息日志
          await InterestLogModel.createLog({
            billId: bill.id,
            billName: bill.name,
            beforePrincipal,
            beforeInterest,
            currentInterest,
            afterInterest,
            count,
            operator: uid.toString(),
            operatorName: ctx.auth.nickname || '',
            status: 'success'
          }, { transaction })

          // 插入成功日志
          results.push({
            billId: bill.id,
            name: bill.name,
            currentInterest,
            status: 'success'
          })
          successCount++

          /** 
           * 更新账单数据
           * 1. 利息总额
           * 2. 剩余利息
           * 3. 下次利息 只记一次
           * 4. 下次计息周期 = 上次计息日期 + 可计次数 + 1
           * 5. 记录操作
           */
          const updateData: any = {
            totalInterest: beforeTotalInterest + currentInterest,
            remainingInterest: afterInterest,
            nextInterest: RecordModel.calculateInterest(bill.rate, beforePrincipal, 1),
            nextDate: DateUtil.formatDate(DateUtil.addMonthsOrDays(lastInterestDate, count + 1, bill.rateType === 'M' ? 'month' : 'day')),
            hasRecord: true
          }
          await billInstance.update(updateData, { transaction })
        } catch (error: any) {
          const bill = billInstance.toJSON()
          console.error(`账单 ${bill.name} 计息失败:`, error)
          // 创建失败日志
          await InterestLogModel.createLog({
            billId: bill.id,
            billName: bill.name,
            beforePrincipal: Number(bill.principal),
            beforeInterest: Number(bill.remainingInterest),
            currentInterest: 0,
            afterInterest: Number(bill.remainingInterest),
            operator: uid.toString(),
            operatorName: ctx.auth.nickname || '',
            status: 'fail',
            error: error.message
          }, { transaction })

          results.push({
            billId: bill.id,
            name: bill.name,
            error: error.message,
            status: 'fail'
          })
          failCount++
        }
      }
    })

    throw new global.errs.Success({
      total: bills.length,
      success: successCount,
      fail: failCount,
      results
    }, null, '计息完成')
  }
} 